/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.component.editpart;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.tools.CellEditorLocator;
import org.eclipse.gef.tools.DirectEditManager;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Port;

import com.cea.papyrus.core.directedit.ILabelControler;
import com.cea.papyrus.core.directedit.LabelCellEditorLocator;
import com.cea.papyrus.core.directedit.LabelControler;
import com.cea.papyrus.core.directedit.LabelDirectEditManager;
import com.cea.papyrus.core.directedit.PropertyAccessor;
import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.editpart.ContainerHighlightEditPolicy;
import com.cea.papyrus.core.editpart.ContainerWithSemanticEditPart;
import com.cea.papyrus.core.figures.IconFigure;
import com.cea.papyrus.core.figures.NodeFigure;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagram.component.figure.ComponentFigure;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;
/**
 * Manages the model of an execution environment.
 * 
 * @author Agnes Lanusse
 * @since mai 07
 */
public class ComponentEditPart extends ContainerWithSemanticEditPart {
	/**
	 * Debug channel for edit parts.
	 */
	private int channel = 202;
	/**
	 * Manager for editing Component name.
	 */
	private DirectEditManager manager;
	


	public ComponentEditPart(GraphNode graphNode, ModelManager modelManager) {
		super(graphNode, modelManager);
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.editpart.ContainerWithSemanticEditPart#createEditPolicies()
	 */
	/**
	 * 
	 */
	@Override
	protected void createEditPolicies() {
		super.createEditPolicies();
		installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE,
				new ContainerHighlightEditPolicy());
		if(getContentPane() != null) {
			installEditPolicy(EditPolicy.LAYOUT_ROLE, new ComponentLayoutEditPolicy(
					(XYLayout) getContentPane().getLayoutManager()));
		}
	
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.cea.papyrus.common.editpart.GraphNodeWithSemanticEditPart#createFigure()
	 */

	@Override
	protected IFigure createFigure() {
		// Force initialization of the manager when figure has changed
		manager = null;	
		// Try to get figure from ContainerWithSemanticEditPart
		IFigure fig = super.createFigure();
		if (fig != null) {
			return fig;
		}
		return new ComponentFigure();
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.cea.papyrus.common.editpart.GraphNodeWithSemanticEditPart#getUmlElement()
	 */

	@Override
	public org.eclipse.uml2.uml.Component getUmlElement() {
		Element e=((Uml1SemanticModelBridge)getGraphNode().getSemanticModel()).getElement();
		// case of element import
		if(e instanceof ElementImport){
			return (org.eclipse.uml2.uml.Component)((ElementImport) e).getImportedElement();
		}
		// this is a simple Component
		return (org.eclipse.uml2.uml.Component)e;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
	 */

	@Override
	protected void refreshVisuals() {
		Debug.debug(this, "refreshvisuals", channel);

		Dimension size = getGraphNode().getSize();
		Point p = getGraphNode().getPosition();
		Rectangle r = new Rectangle(p ,size);

		IFigure fig = getFigure();

		// if fig is a stereotype figure
		if (!(fig instanceof ComponentFigure)) {
			IconFigure icf= (IconFigure)getFigure();
			icf.setName(((NamedElement)getUmlElement()).getName());

		} else {
			// Retrieve current component and figure
			org.eclipse.uml2.uml.Component currentComponent = getUmlElement();
			com.cea.papyrus.umlutils.Element currentElement = new com.cea.papyrus.umlutils.Element(getUmlElement());

			ComponentFigure f = (ComponentFigure) fig; //get Component figure
			
			// if fig is a ClassFigure
			((NodeFigure) fig).refreshColors(getGraphNode());
			((NodeFigure) fig).refreshPresentation(getPresentation(), currentComponent, getGraphNode());
			boolean hasIcon  = currentElement.hasIcon();
			boolean hasShape = currentElement.hasShape();
			
			//f.refreshStereotypes(currentElement.getStereotypes(), getPresentation(), hasIcon, hasShape);
			f.refreshStereotypes(f.stereotypesLabel(this), getPresentation(), hasIcon, hasShape);
		
			f.setName(currentComponent.getName());// set the name of the class

			// refresh qualifiedName
			GraphNode gp= (GraphNode)getGraphNode().getContainer();
			f.refreshQualifiedName(gp, getGraphNode(), getUmlElement());
			
		}

		((GraphicalEditPart) getParent()).setLayoutConstraint(
				this,
				fig,
				r);

	}


	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getContentPane()
	 */

	@Override
	public IFigure getContentPane() {
		IFigure fig = getFigure();
		if(fig instanceof ComponentFigure) {
			return ((ComponentFigure)fig).getContentsPane();
		}
		return null;
	}

	protected Label getNameLabel() {
		IFigure fig = getFigure();

		if (fig instanceof IconFigure) {
			return (Label) fig;
		} else if (fig instanceof ComponentFigure) {
			return ((ComponentFigure) fig).getNameLabel();
		} else {
			Debug.debug(this, "ComponentEditPart::getNameLabel() : Unknown Figure type.", channel);
			return null;
		}
	}


//	public void performDirectEdit(Request req) {
//		initLabelEditManager();
//		manager.show();
//	}

	/**
	 * Init the label direct edit manager.
	 * This method should be called when a Direct Edit request is performed.
	 */
	protected void initLabelEditManager() {
		if(manager==null) {
			// locator for the cell editor (on the name label)
			CellEditorLocator locator = new LabelCellEditorLocator(getNameLabel());

			// defining how properties are modified in the model
			PropertyAccessor accessor = new PropertyAccessor() {
				public String getPropertyName() {
					return "Name";
				}

				public String getValue() {
					return getUmlElement().getName();
				}
				public void setValue(String value) {
					getUmlElement().setName(value);  
				}
			};
			// defines the controller: link between model and view
			ILabelControler labelControler = new LabelControler(getNameLabel(), accessor);

			// creates the editing manager.
			manager = new LabelDirectEditManager(this, locator, labelControler);
		}
	}
	/**
	 * the direct edit mechanism requires the edit part to handle the direct edit
	 * request.
	 * 
	 * @param req the request that called the direct edit.
	 */
	public void performDirectEdit(Request req) {
		initLabelEditManager();
		manager.show();
	}
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractEditPart#performRequest(org.eclipse.gef.Request)
	 */

	@Override
	public void performRequest(Request request){
		if (RequestConstants.REQ_DIRECT_EDIT.equals(request.getType())) {
			performDirectEdit(request);
		}
	}
	@Override
	protected List getModelChildren() {
		ArrayList contained= new ArrayList();
		ArrayList ports= new ArrayList();
		ArrayList labels=new ArrayList();
		// if the presentation of the element is not shape we can display children, otherwise we can't
		if(getGraphNode().getSemanticModel() != null) {
			if((getGraphNode().getSemanticModel().getPresentation()==null) ||
					!(getGraphNode().getSemanticModel().getPresentation().equals(ModelerHelper.IMAGE_STEREOTYPE_PRESENTATION))) {
				Iterator it=getGraphNode().getContained().iterator();
				while (it.hasNext()){
					GraphElement ge=(GraphElement)it.next();
				    Element ue = null; 
				    
				    if (!(ge instanceof GraphEdge) ) {
						if ( ((GraphNode)ge).getSemanticModel() != null ) {			    		
							if (((Uml1SemanticModelBridge) ((GraphNode)ge).getSemanticModel()).getElement() != null) {
								ue = ((Uml1SemanticModelBridge) ((GraphNode)ge).getSemanticModel()).getElement();
								if (ue instanceof  Port) {
									ports.add(ge);        // Ports will be added later to be displayed on top
								}
								else {
									contained.add(ge);
								}
							} else { //element is null (should not happen)
								//contained.add(ge);
							}					    	
						} else {  // semanticModel is null (can be a comment link for instance)
							labels.add(ge);
						}
					}
				    // if it is a graphEdge there is nothing to do
				    // GEF will take care ...				   
				}
			}
		}
		// Now we can add ports	and labels	
		contained.addAll(labels);
		contained.addAll(ports);
		return contained;
	}
}